Loading...
Loading...
Loading...

目录


python高级| 多任务:进程,线程,协程

计算机编程 发布于:2022/3/17/13:38 909 vk python 多线程 协程 多任务 多进程 最近编辑于2 年,9 月前 预计阅读时长:9min


文章于2021年2月23日首发于我的公众号:vk的python不安全,公众号文章链接:python高级| 多任务:进程,线程,协程

多任务

简单地说,就是操作系统可以同时执行多个任务。在代码里面,就是一个程序有多个地方同时执行,打个比方,你一边用着这浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务

多任务分为并行并发

    并行(真的多任务),比如:有两个任务要同时进行,而cpu内核是4核的时候,这两个任务就会真正的同时分配给其中两个内核来完成。

    当任务数量大于内核数量的时候就不能这么干了,因为cpu内核为n时最多同时运行n个任务。

    这时候就变成了并发(假的多任务)由于cpu处理的速度很快,它采用一种轮转的方式。一个任务执行一段时间后扔一边又去执行另一个任务。这样来回转,雨露均沾。以达到类似于同时进行的效果

 

进程:就是一个运行着的程序,多进程,就是一个程序能同时制造多个进程。比如同时打开qq和酷狗音乐

多线程:在同一个进程里干两件事,比如:在酷狗音乐里同时听歌和下载歌曲。

故事时间:

  从前啊,有一个工地,堆放一堆材料,后面有很多工人,但是工人只能排成一列,因为那个过道太窄,只能由一个工人真正操作那堆材料。后来,任务量大了,老板就派人把那个过道弄宽了,这下可以很多工人同时操作那个材料了。
 

    慢慢的,越做越大,这些也满足不了需求,因为人很多,但是是共享材料的。老板就又买了批材料,雇了批工人。两批工人,两批材料,两个地方同时开工大大提高了生产效率。

    但是每次买新的材料,雇新的工人很耗费精力。有时候工人不断工作,把材料消耗完了,抽根烟等待塔吊把新的材料运过来,为了提高效率,老板让工人利用等待的时间去隔壁和水泥去了。

    快年底了,工人们为了冲业绩,争先恐后地拿那些材料,他们的任务是用这些材料把一个东西从头组装到尾,但是由于他们抢材料,头还在制作中,就有人开始组装尾部了,老板后来就给了他们一把锁和一个盒子,一个人用的时候就锁上,不让其他人用。
 

 

上述这些事情总结出来就是:

 

进程之间不共享全局变量

线程之间共享全局变量,但是要注意资源竞争的问题,解决办法:互斥锁

创建进程的资源开销要比创建线程的资源开销要大

进程是操作系统的资源分配的基本单位,线程是CPU调度的基本单位

线程不能够独立执行,必须依存在进程中

多线程开发比单进程多进程开发稳定性要强

   线程与进程的优缺点

进程优缺点


优点:可以使用多核
缺点:资源开销大

线程优缺点


优点:资源开销小
缺点:不能使用多核

    那么问题来了,python的多线程为什么不能使用多核呢?


 

    也就是python中的多线程为什么不能同时进行呢?这就是传说的GIL锁(全局解释锁)。多线程并不能真的的同步运行,同一时刻,只能运行一个线程,多线程是以轮转的方式运行,看似是多进程,实则非也。

    python 垃圾?动态语言很废?不不不,python可不背这个锅,都是cpython惹的祸,python语言本来没有GIL锁的,出现这样的问题python解释器cpython。

    而大多数包括官网给解释器的就是cpython 。GIL因为历史遗留问题,为了保护资源考虑的,python之父GuiDo大佬之前尝试去掉这个。

  可是发现去掉之后python的效率慢了很多,得不偿失所以,GIL至今还有。

线程锁:  之前故事中,老板为了避免抢资源上的锁

有了GIL是不是就不用线程锁了呢?

    

    Of course not!线程锁的作用是在一个线程利用这个资源的时候别的线程不会抢,而GIL只是保证了同一时刻不会有两个线程运行,如果不用线程锁,说不定你回头挠痒痒的时候,隔壁大哥就把你的资源用了

   既然多线程不能同时运行,还要开销资源,有时候比单线程还慢。要它干什么呢?

 在计算密集型    也就是利用cpu的算力来计算一些东西的程序中,python的多线程确实很废,如果是计算密集型的程序不要用python的多线程,要用就用多进程。或者直接不要用python。用更快的c,c++那些。


 

    但是I/O密集型     也就是(input/output),在有文件的读写操作时可以用python的多线程,比如爬虫,在爬完一段数据,往文件里写入的同时,可以继续爬取其他数据。在图形界面中也可以用多线程,比如按下按钮,运行程序程序计算一堆数据,如果数据没有算出来,按钮就会卡住,图形界面也会卡住,直到数据计算完成,这时候给计算数据的部分开一个新的线程,就不会出现这种情况了。


 

    要是强迫症非要解决GIL,也不是不行,可以换用Jython,用java实现的解释器,或者通过python调用c语言打dll也是可以解决的。


协程

    多线程,多进程两者各有利弊,有没有个折中点的东西呢,有!协程。在工地干活那个例子中,老板让工人等待材料的时间去和水泥就类似于协程。协程是包含于线程的


 


 

    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

    线程  的具体行为是由内核操作的,什么时候运行什么部分,这个部分运行多长时间,都不受用户控制。
 

    协程  是在程序层面操作的,可以控制遇到阻塞的时候候程序该干什么。在写web服务器的时候非常有用。
 

科普一下:
 

1、同步阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,期间你一直在接听电话。
 

2、同步非阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,你期间吃了个西瓜(打电话没有影响你做其他事,显示运用中也很难遇到)。
 

3、异步非阻塞:你打电话给114查路线,客服说查好之后打给你,这期间你可以做任何事。
 

4、异步阻塞:你打电话给114查路线,客服说查好之后打给你,但这期间你什么都没做,等到回复电话之后,再继续下一步动作。(是不是很傻)现实运用中,异步阻塞是没有意义的!

 

    如果一个服务器是同步的话,在安全方面很有问题,比如客户发过来很多信息,没有及时处理,这时候就会存在缓冲区溢出的漏洞。假设,一个程序的登录中输入密码部分没有及时处理,就会被植入shellcode 利用kali生成一个简单的shellcode 。


 

 

    然后计算好什么时候开始溢出的,将生成的恶意代码写入输入密码框中,这时候,本来为空白的寄存器就被植入了有实际作用的代码,然后利用JMP指令跳转到有恶意代码的地址,当程序打开后,就会自动打开植入的恶意程序。
 

单词数:70字符数:2800

共有0条评论